#!/bin/bash

# 首先看一下 compgen 的用法
# compgen：
    # 用法：compgen [-abcdefgjksuv] [-o 选项]  [-A 动作] [-G 全局模式] [-W 词语列表]  [-F 函数] [-C 命令] [-X 过滤模式] [-P 前缀] [-S 后缀] [词语]


# 在补全脚本中, COMPREPLY 是一个包含 compgen 结果的变量，这也是最终提供给到命令补全的结果

    # 例如：我们使用 cat /etc/passwd | awk -F ":" '{print $1}' 来输出一个用户列表
        
        # 它会输出一些预期结果，这是用户列表，用 USERS 变量装起来
            # root
            # daemon
            # sys
            # sshd
            # lightdm
            # sync

            # 注意这些内容是没有 ' ' 空格分隔的，基本上就是连续词

    USERS=`cat /etc/passwd | awk -F ":" '{print $1}'`

    COMPREPLY=(
        $(compgen -W "${USERS}" -- s)
    )
        
        # 它会输出正常的预期的内容
            # sys
            # sshd
            # sync


# 为了准备接下来的 bullshit，先概述一下关于 USERS[@] 与 USERS[*] 的内容，其中包含 IFS.

    # 这里使用 COMPREPLY 中的结果，它是一个数组，有刚刚的 3 个元素

    ehco "${COMPREPLY}"
        # sys
        
        # 它会输出一个 sys，不达预期，因为是一个数组，只使用 ${array} 则只会输出第一个值
    
    echo "${COMPREPLY[@]}"
        # sys sshd sync

    echo "${COMPREPLY[*]}"
        # sys sshd sync

    # 从 ${array[@]} 与 ${array[*]} 的输出中，感觉不到明显的差别，但这是一个区别非常大的东西


    IFS=','

        # 当 IFS 被设置为 ',' 逗号时，两个输出的区别则会明显

        echo "${COMPREPLY[@]}"
            # sys sshd sync
        
        echo "${COMPREPLY[*]}"
            # sys,sshd,sync

    # 注意，这里始终使用的是 " " 进行包围变量结果的形式

unset IFS




# 这里开始 bullshit 的准备，假设我有一个需要参与补全的结果，它是有空格的

    cat ./result.txt
        # RFC 1928 - SOCKS 5 协议中文文档「译」
        # github release 加速下载
        # M-Team - 一个 BT 论坛
        # fetch-latest-vscode-amd64-deb
        # https://mirror.ghproxy.com/
        # frp 相关内容
        # 小白安装 Gentoo 简述(不错的文章)
        # Ipv6 连接测试网页
        # connect-Mi10
        # Dockerfile 文件详解
        # Jenkins 下载页面

    
    # 这里，我以变量形式装起来

    SUPPLY=`cat ./result.txt`

    # 如果使用 compgen -W "${SUPPLY}" ... 来直接尝试补全 fetch-latest-vscode-amd64-deb
        
        compgen -W "${SUPPLY}" fetch
            # fetch-latest-vscode-amd64-deb
        
            # 它的输出结果是正确的

        compgen -W "${SUPPLY}" connect
            # connect-Mi10

            # 它的输出结果是正确的
            

    # bullshit 开始
        compgen -W "${SUPPLY}" github
            # github

            # 它的输出结果是错误的，疑似是结果中的空格成为了分隔符

        compgen -W "${SUPPLY}" I
            # Ipv6

            # 它的输出结果仍是错误的

        compgen -W "${SUPPLY}" RFC
            # RFC

            # 它的输出结果仍是错误的

        # 这里的输出的结果，不达预期，连续部分输出的结果是正常的，包含空格的部分则是有问题的

    
    IFS=$'\n'
        # 注意这里的 $'\n'，意思是让 '\n' 作为一个 IFS 的单字符值。
            # 如果没有 $ 符号则 IFS='\n' 表示 '\n' 是一个字符串，也等效于 IFS="\n"，字符串值无法在后续结果中产生效果

        # 再来测试补全结果
            compgen -W "${SUPPLY}" I
                # Ipv6 连接测试网页

            compgen -W "${SUPPLY}" RFC
                # RFC 1928 - SOCKS 5 协议中文文档「译」

            compgen -W "${SUPPLY}" fetch
                # fetch-latest-vscode-amd64-deb

            compgen -W "${SUPPLY}" 小白
                # 小白安装 Gentoo 简述(不错的文章)

        # 经过 IFS 设置后，这里的补全结果是正常的

    # 如果只是 compgen，这样就已经是 bullshit 预期的解决方案

        # 如果要涉及到实际的命令行补全结果，例如
            
            COMPREPLY=(
                $(compgen -W "${SUPPLY}" RFC)
            )
            
            # <命令> <get> RFC 1928 - SOCKS 5 协议中文文档「译」
            #                ^ --------- 补全内容 ---------- ^
            #       ^ 次级命令
            # ^ 主命令
        
            # 这种预期结果是不可行的，次级命令接收的参数并非是一个整体的字符串参数，所以需要对 COMPREPLY 的内容进行处理

            for (( i=0; i<${#COMPREPLY[@]}; i++ )); do
                COMPREPLY[$i]="'${COMPREPLY[i]}'"
                # 给每一个结果都加入 '' 单引号包围
            done

            # <命令> <get> 'RFC 1928 - SOCKS 5 协议中文文档「译」'
            #             ^   ^ --------- 补全内容 ----------- ^
            #       ^ 次级命令
            # ^ 主命令

            # 这样，预期的结果次级命令接收的参数是一个整体的字符串参数，可达预期

    unset IFS


# bullshit 关键点：
    # 补全脚本如果涉及多行、包含空格的命令输出式结果形式的内容，一般形式写法可能会产生非预期行为

    # 来自 man bash 的解释，但它却没有细说

        # IFS    内部字段分隔符    Internal    Field    Separator     用来在扩展之后进行分词，使用内部命令     read     将行划分成词。默认值是
            # ``<space><tab><newline>''。



# IFS 可能只适用于 linux bash shell 内部使用，而 bash 补全脚本正是运行在 bash 内部，提供命令强大的补全能力